import 'dart:convert';
import 'dart:ui';

import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:htxd_flutter_mapbox_sdk/mapbox/util/jts_geometry_util.dart';
import 'package:htxd_flutter_mapbox_sdk/mapbox/util/turf_geometry_util.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';

import '../../../contract.dart';
import '../../mapview/base_map_control.dart';
import '../../util/number_util.dart';
import '../entity/array_stack.dart';
import '../entity/land_entity.dart';

/// 测面积
class MeasureLength {
  // 点资源
  static const String _POINT_SOURCE = "point_source";
  static const String _POINT_LAYER = "point_layer";

  // 选中的点
  static const String _SELECT_POINT_SOURCE = "select_point_source";
  static const String _SELECT_POINT_LAYER = "select_point_layer";

  // 线资源
  static const String _LINE_SOURCE = "line_source";
  static const String _LINE_LAYER = "line_layer";

  // 长度 资源
  static const String _LENGTH_SOURCE = "length_source";
  static const String _LENGTH_LAYER = "length_layer";

  // control 控制类
  final MapBoxControl? _mapBoxControl;

  StyleManager? _style;

  // 数据存储栈
  late ArrayStack<LandEntity> _landOperas;

  // 数据点集合
  late List<Position> _positions;

  // uuid ，唯一标识
  late final String _uuid;

  // 选择的 index 下标
  int _selectIndex = -1;

  MeasureLength(this._mapBoxControl, this._uuid) {
    _landOperas = ArrayStack();
    _positions = [];
    _style = _mapBoxControl?.style;
  }

  /// 添加点
  void add(Position position) {
    _landOperas.push(LandEntity(_selectIndex, _positions));
    _positions.add(position);
    _selectIndex = _positions.length;
    _draw();
  }

  /// 删除
  Future<void> delete() async {
    _positions.clear();
    _landOperas.clear();
    await _clear();
  }

  /// 是否可以撤销
  bool isUndo() {
    return _landOperas.stack.isNotEmpty;
  }

  /// 撤销
  void undo() {
    if (isUndo()) {
      LandEntity pop = _landOperas.pop();
      _positions.clear();
      _positions.addAll(pop.positions);
      _selectIndex = pop.selectPosition;
      _draw();
    }
  }

  /// 是否触摸到点上面
  Future<bool> touchPoint(ScreenCoordinate coordinate) async {
    if (_mapBoxControl == null) {
      return false;
    }
    for (int i = 0; i < _positions.length; i++) {
      var screen = await _mapBoxControl!.positionToScreen(_positions[i]);
      if ((coordinate.x - screen.x).abs() < 20.w &&
          (coordinate.y - screen.y).abs() < 20.w) {
        if (i != _selectIndex - 1) {
          _selectIndex = i + 1;
        }
        return true;
      }
    }
    return false;
  }

  /// 开始移动
  void startMove() async {
    _landOperas.push(LandEntity(_selectIndex, _positions));
    await _clear();
  }

  /// 结束移动
  void endMove(ScreenCoordinate coordinate) async {
    if (_mapBoxControl == null) {
      return;
    }
    var position = await _mapBoxControl!.screenToPosition(coordinate);
    _positions[_selectIndex - 1] = position;
    _draw();
  }

  /// 完成操作
  void complete() async {
    await _clear();
    await _drawLine();
    await _drawLength();
  }

  // 绘制
  Future<void> _draw() async {
    await _clear();
    await _drawLine();
    await _drawPoint();
    await _drawSelectPoint();
    await _drawLength();
  }

  Future<void> _drawLength() async {
    if (_positions.length <= 1) {
      return;
    }
    List<Position> pointList = [];
    pointList.addAll(_positions);
    pointList.add(pointList[0]);

    double length = TurfGeometryUtil.calculateLength(_positions);
    Position center = JtsGeometryUtil.getGeometryCenter(pointList);
    Point point = Point(coordinates: center);

    GeoJsonSource source = GeoJsonSource(
        id: '$_uuid$_LENGTH_SOURCE',
        data: jsonEncode(Feature(id: "", geometry: point).toJson()));
    await _style?.addSource(source);

    var layer = {
      "id": "$_uuid$_LENGTH_LAYER",
      "source": "$_uuid$_LENGTH_SOURCE",
      "type": "symbol",
      "layout": {
        "text-size": Contract.LAND_AREA_SIZE,
        'text-field': '${NumberUtil.getValue(length, 2)}米'
      },
      "paint": {
        "text-color": "rgba(0, 0, 0, 255)",
        "text-halo-blur": 1.0,
        "text-halo-color": "rgba(255, 255, 255, 255)",
        "text-halo-width": 2.w
      }
    };
    await _style?.addStyleLayer(json.encode(layer), null);
  }

  Future<void> _drawLine() async {
    if (_positions.length <= 1) {
      return;
    }
    List<Position> points = [];
    points.addAll(_positions);
    LineString lineString = LineString(coordinates: points);
    GeoJsonSource jsonSource = GeoJsonSource(
        id: '$_uuid$_LINE_SOURCE',
        data: jsonEncode(Feature(id: '', geometry: lineString).toJson()));
    _style?.addSource(jsonSource);
    LineLayer lineLayer = LineLayer(
        id: '$_uuid$_LINE_LAYER',
        sourceId: '$_uuid$_LINE_SOURCE',
        lineColor: Contract.LAND_LINE_COLOR.value,
        lineWidth: Contract.LAND_LINE_WIDTH);
    _style?.addLayer(lineLayer);
  }

  // 画点
  Future<void> _drawSelectPoint() async {
    if (_positions.isEmpty) {
      return;
    }
    int index = _selectIndex - 1;
    if (index < 0 && index >= _positions.length) {
      return;
    }
    Feature<Point> feature =
        Feature(id: '', geometry: Point(coordinates: _positions[index]));
    GeoJsonSource jsonSource = GeoJsonSource(
        id: '$_uuid$_SELECT_POINT_SOURCE', data: jsonEncode(feature.toJson()));
    _style?.addSource(jsonSource);
    CircleLayer circleLayer = CircleLayer(
      id: '$_uuid$_SELECT_POINT_LAYER',
      sourceId: '$_uuid$_SELECT_POINT_SOURCE',
      circleRadius: 8,
      circleColor: const Color(0xFFFF0000).value,
      circleStrokeColor: Contract.LAND_POINT_COLOR.value,
      circleStrokeWidth: 4,
    );
    _style?.addLayer(circleLayer);
  }

  // 画点
  Future<void> _drawPoint() async {
    if (_positions.isEmpty) {
      return;
    }
    List<Feature<Point>> features = [];
    for (var position in _positions) {
      features.add(Feature(id: '', geometry: Point(coordinates: position)));
    }
    GeoJsonSource jsonSource = GeoJsonSource(
        id: '$_uuid$_POINT_SOURCE',
        data: jsonEncode(FeatureCollection(features: features).toJson()));
    _style?.addSource(jsonSource);
    CircleLayer circleLayer = CircleLayer(
      id: '$_uuid$_POINT_LAYER',
      sourceId: '$_uuid$_POINT_SOURCE',
      circleRadius: Contract.LAND_POINT_WIDTH,
      circleColor: Contract.LAND_POINT_COLOR.value,
    );
    _style?.addLayer(circleLayer);
  }

  // 清除
  Future<void> _clear() async {
    await _deleteSourceAndLayer(
        '$_uuid$_LENGTH_SOURCE', '$_uuid$_LENGTH_LAYER');
    await _deleteSourceAndLayer('$_uuid$_POINT_SOURCE', '$_uuid$_POINT_LAYER');
    await _deleteSourceAndLayer(
        '$_uuid$_SELECT_POINT_SOURCE', '$_uuid$_SELECT_POINT_LAYER');
    await _deleteSourceAndLayer('$_uuid$_LINE_SOURCE', '$_uuid$_LINE_LAYER');
  }

  // 删除source和layer
  Future<void> _deleteSourceAndLayer(String sourceId, String layerId) async {
    if (await _style?.styleLayerExists(layerId) == true) {
      await _style?.removeStyleLayer(layerId);
    }
    if (await _style?.styleSourceExists(sourceId) == true) {
      await _style?.removeStyleSource(sourceId);
    }
  }

  int get selectIndex => _selectIndex;

  List<Position> get positions => _positions;
}
